﻿using CodeMapper.Mappers;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Test.Models;

namespace Test
{
    class Program
    {
        private static JsonSerializerSettings serializerSettings = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            NullValueHandling = NullValueHandling.Ignore,
            DateFormatString = "yyyy-MM-dd HH:mm:ss",
            Formatting = Formatting.Indented
        };
        private static void Log(object obj, string message)
        {
            var str = JsonConvert.SerializeObject(obj, serializerSettings);
            Console.WriteLine($"{message}:\r\n{str}");
        }
        static void Main(string[] args)
        {
            try
            {
                //TestConfig();

                //TestLoop();
                //TestIgnore();
                //TestDepth(3);
                //TestDepth(2);

                TestYP();
                Console.WriteLine("all test end");
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }

            Console.Read();
        }

        static Model1 GetTestModel()
        {
            var model = new Model1
            {
                ID = 1,
                ByteInt = 2,
                ByteString = 3,
                Name = "test",
                M1 = new M1
                {
                    ID = 12,
                    Name = "innermodel"
                },
                Items = new List<Item1>
                {
                    new Item1
                    {
                        ID=2,
                        Name="testitem"
                    },
                    new Item1
                    {
                        ID=3,
                        Name="testitem2"
                    },
                },
                Datas = new List<byte> { 1, 2, 3, 4 }
            };

            model.M1.Parent = model;
            model.Items.ForEach(x => x.Parent = model);
            return model;
        }

        static SupplierModel GetSupplier()
        {
            var fss = new List<FactoryModel>();
            for(int i = 0; i < 3; i++)
            {
                var f = new FactoryModel
                {
                    ID = Guid.NewGuid().ToString(),
                    AuditStatus = 1,
                    AuditTime = DateTime.Now,
                    AuditUserID = "aa",
                    AuditUserName = "user",
                    Code = "d",
                    Contacts1 = "222",
                    Contacts2 = "2222",
                    Conventional = "2222",
                    ConventionalEMail = "2222",
                    ConventionalTel = "2222",
                    DetailAddr = "2222",
                    EMail1 = "2222",
                    EMail2 = "2222",
                    EnableEdit = 1,
                };
                var fccs = new List<FactoryCertModel>();
                for(int j = 0; j < 3; j++)
                {
                    fccs.Add(new FactoryCertModel
                    {
                        AuditStatus = (byte)i,
                        CertDateTime = DateTime.Now,
                        ID = Guid.NewGuid().ToString(),
                        FactoryID = f.ID,
                        Factory = f
                    });
                }
                f.FactoryCerts = fccs;
                fss.Add(f);
            }


            var sccs = new List<SupplierCertModel>();
            for(int i = 0; i < 3; i++)
            {
                sccs.Add(new SupplierCertModel
                {
                    AuditStatus = (byte)i,
                    CertDateTime = DateTime.Now,
                    ID = Guid.NewGuid().ToString(),
                    SupplierCertPictures = new List<SupplierCertPictureModel>
                    {
                        new SupplierCertPictureModel{ID=Guid.NewGuid().ToString(),},
                        new SupplierCertPictureModel{ID=Guid.NewGuid().ToString(),},
                        new SupplierCertPictureModel{ID=Guid.NewGuid().ToString(),}
                    }
                });
            }
            var sp = new SupplierModel
            {
                ID = Guid.NewGuid().ToString(),
                AuditStatus = 1,
                AuditTime = DateTime.Now,
                AuditUserID = "aa",
                AuditUserName = "user",
                Code = "d",
                Contacts1 = "222",
                Contacts2 = "2222",
                Conventional = "2222",
                ConventionalEMail = "2222",
                ConventionalTel = "2222",
                DetailAddr = "2222",
                EMail1 = "2222",
                EMail2 = "2222",
                Factorys = fss,
                SupplierCerts = sccs
            };
            fss.ForEach(x =>
            {
                x.SupplierID = sp.ID;
                x.Supplier = sp;
            });
            sccs.ForEach(x =>
            {
                x.SupplierID = sp.ID;
                x.Supplier = sp;
                x.SupplierCertPictures.ForEach(p => p.SupplierCert = x);
            });

            return sp;
        }


        public static void TestConfig()
        {
            CodeMapper.Mapper.Config(config =>
            {
                config.ReferencePropertyHandle = CodeMapper.Metas.ReferencePropertyHandle.Loop;
                config.MaxDepth = 10;
                config.BindWhenNeed = true;
                config.SetNameMatching(NameMatching);

                //config.SetObject2String(x => JsonConvert.SerializeObject(x, serializerSettings));

                //config.SetLogger(Console.WriteLine);
            });
            //CodeMapper.Mapper.BindCustom<Model1, Model2>(b => new Model2
            //{
            //    IDModel = b.ID,
            //    ByteInt = 1
            //});

            //CodeMapper.Mapper.Bind<Model1, Model2>(b =>
            //{
            //    b.Bind(x => x.Name, x => x.Name + "111");
            //    b.Bind(x => x.Name, x => "111");
            //    b.Bind(x => x.Name, x => x.Name);
            //    b.Ignore(x => x.IDModel);
            //});
            var model = GetTestModel();
            var model2 = CodeMapper.Mapper.Map<Model1, Model2>(model);
            var model1 = CodeMapper.Mapper.Map<Model2, Model1>(model2);

            var supp = GetSupplier();
            Supplier s = null;
            var st = Stopwatch.StartNew();
            s = CodeMapper.Mapper.Map<SupplierModel, Supplier>(supp);
            st.Stop();
            Console.WriteLine("耗时" + st.ElapsedMilliseconds);
            st.Restart();
            s = CodeMapper.Mapper.Map<SupplierModel, Supplier>(supp);
            st.Stop();
            Console.WriteLine("耗时" + st.ElapsedMilliseconds);
            st.Restart();
            s = CodeMapper.Mapper.Map<SupplierModel, Supplier>(supp);
            st.Stop();
            Console.WriteLine("耗时" + st.ElapsedMilliseconds);
            st.Restart();
            s = CodeMapper.Mapper.Map<SupplierModel, Supplier>(supp);
            st.Stop();
            Console.WriteLine("耗时" + st.ElapsedMilliseconds);
            st.Restart();
        }

        static bool NameMatching(string x, string y)
        {
            if(x.Equals(y, StringComparison.OrdinalIgnoreCase))
                return true;
            if(x + "Model" == y)
                return true;
            if(y + "Model" == x)
                return true;
            if(x.Replace("Models", "s") == y)
                return true;
            if(y.Replace("Models", "s") == x)
                return true;
            return false;
        }

        static void TestIgnore()
        {
            Console.WriteLine("测试映射效率：ReferencePropertyHandle=Ignore");
            CodeMapper.Mapper.Config(config =>
            {
                config.ReferencePropertyHandle = CodeMapper.Metas.ReferencePropertyHandle.Ignore;
                config.BindWhenNeed = true;
                config.SetNameMatching(NameMatching);
            });
            LoopTest(10000, 10);
        }

        static void TestLoop()
        {
            Console.WriteLine("测试映射效率：ReferencePropertyHandle=Loop");
            CodeMapper.Mapper.Config(config =>
            {
                config.ReferencePropertyHandle = CodeMapper.Metas.ReferencePropertyHandle.Loop;
                config.BindWhenNeed = true;
                config.SetNameMatching(NameMatching);
            });
            LoopTest(10000, 10);
        }

        static void TestDepth(int depth)
        {
            Console.WriteLine("测试映射效率：ReferencePropertyHandle=Depth: " + depth);
            CodeMapper.Mapper.Config(config =>
            {
                config.ReferencePropertyHandle = CodeMapper.Metas.ReferencePropertyHandle.Depth;
                config.MaxDepth = depth;
                config.BindWhenNeed = true;
                config.SetNameMatching(NameMatching);
            });
            LoopTest(10000, 10);
        }

        static void LoopTest(int modelCount, int count)
        {
            Console.WriteLine($"模型数 {modelCount}，循环数{count}");
            var model = GetSupplier();
            var list1 = new List<SupplierModel>();
            var j = JsonConvert.SerializeObject(model, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore });
            for(int i = 0; i < modelCount; i++)
            {
                var m = JsonConvert.DeserializeObject<SupplierModel>(j);
                list1.Add(m);
            }
            list1.ForEach(x =>
            {
                x.Factorys.ForEach(f =>
                {
                    f.Supplier = x;
                    f.FactoryCerts.ForEach(c => c.Factory = f);
                });
                x.SupplierCerts.ForEach(c =>
                {
                    c.Supplier = x;
                    c.SupplierCertPictures.ForEach(p => p.SupplierCert = c);
                });
            });
            for(int i = 0; i < count; i++)
            {
                var st = Stopwatch.StartNew();
                var list3 = CodeMapper.Mapper.Map<SupplierModel, Supplier>(list1);
                var list2 = CodeMapper.Mapper.Map<Supplier, SupplierModel>(list3);
                st.Stop();
                Console.WriteLine("耗时" + st.ElapsedMilliseconds);
            }
        }

        static void TestYP()
        {
            CodeMapper.Mapper.Config(config =>
            {
                config.ReferencePropertyHandle = CodeMapper.Metas.ReferencePropertyHandle.Depth;
                //config.MaxDepth = 2;
                config.BindWhenNeed = true;
                config.SetNameMatching(NameMatching);
            });


            var yp = new JCSJ_YP_ZDYXX
            {
                CGLB = 2,
                CGYKID = "CGYKID",
                CreateTime = DateTime.Now,
                DLCG = true,
                GLBS = 3,
                JJ = 100,
                CGYKMC = "CGYKMC",
                CreaterCode = "CreateCode",
                CreaterID = "CreateID",
                Curr_CustomerID = "Curr_CustomerID",
                GPO = true,
                HISCode = "HisCode",
                ID = "ID",
                ID3 = "ID3",
                JLJCB = 111,
                JYLX = "JYLX",
                KCSX = 100,
                KCXX = 50,
                LSJ = 100,
                MLLX = 1,
                NeedUpToDep = 1,
                QYBZ = true,
                BaseData = new JCSJ_YP_BZXX
                {
                    BWM = "BWM",
                    BZDWID = "BZDWID"
                }
            };

            var model = CodeMapper.Mapper.Map<JCSJ_YP_ZDYXX, JCSJ_YP_ZDYXXModel>(yp);

            var list = new List<JCSJ_YP_ZDYXX>() { yp };
            var models = CodeMapper.Mapper.Map<JCSJ_YP_ZDYXX, JCSJ_YP_ZDYXXModel>(list);
        }
    }
}
